package org.dbstar.scheduler.quartz;

import java.util.Date;

import org.dbstar.scheduler.beans.Job;
import org.dbstar.scheduler.control.JobController;
import org.dbstar.scheduler.control.JobStatusChangeListener;
import org.dbstar.scheduler.identifier.Identifier;
import org.dbstar.scheduler.identifier.IdentifierFactory;
import org.dbstar.scheduler.identifier.IdentifierType;
import org.dbstar.scheduler.job.JobStatus;
import org.quartz.JobDataMap;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Job重试调度器
 * 
 * @author 代波
 * @since 1.0.0
 * @version 1.0.0
 * @date 2012-5-28
 */
public class JobRetryScheduler implements JobStatusChangeListener {
	private static final Logger LOGGER = LoggerFactory.getLogger(JobRetryScheduler.class);

	private final Scheduler scheduler;
	private final IdentifierFactory identifierFactory;

	public JobRetryScheduler(JobController jobController, Scheduler scheduler, IdentifierFactory identifierFactory) {
		super();
		this.scheduler = scheduler;
		this.identifierFactory = identifierFactory;
		// 注册监听器
		jobController.registJobStatusChangeListener(this, null, null, JobStatus.retry);
	}

	@Override
	public void onJobStatusChange(Job job, JobStatus oldStatus, JobStatus newStatus) {
		// 增加重试调度任务
		try {
			scheduler.scheduleJob(buildTrigger(job));
		} catch (Throwable e) {
			LOGGER.error("无法定制调度", e);
		}
	}

	private Trigger buildTrigger(Job job) throws Throwable {
		TriggerBuilder<Trigger> builder = TriggerBuilder.newTrigger().forJob(RetryJob.class.getName());

		// TriggerId
		builder.withIdentity(identifierFactory.createIdentifier(IdentifierType.trigger).getStringIdentifier(), job
				.getJobConfIdentifier().getStringIdentifier());
		// Trigger描述信息
		builder.withDescription("重试(" + job.getRetry() + "/" + job.getMaxRetry() + ")："
				+ job.getIdentifier().getStringIdentifier());

		// 调度：仅执行一次
		builder.withSchedule(SimpleScheduleBuilder.simpleSchedule());

		// 设置JobId
		JobDataMap dataMap = new JobDataMap();
		dataMap.put(Identifier.class.getName() + '.' + IdentifierType.job.name(), job.getIdentifier());
		dataMap.put(Identifier.class.getName(), job.getJobConfIdentifier());
		dataMap.put(RunJobConfJob.JOB_SUBMITTER_KEY, job.getSubmitter());
		if (job.getParameterSize() > 0) {
			dataMap.put(RunJobConfJob.JOB_PARAMETERS_KEY, job.getParameters());
		}
		builder.usingJobData(dataMap);

		// 设置重试开始时间
		switch (job.getRetry()) {
		case 1:
			// 第1次重试为一分钟以后开始执行
			builder.startAt(new Date(System.currentTimeMillis() + 60000));
			break;
		case 2:
			// 第2次重试为三分钟以后开始执行
			builder.startAt(new Date(System.currentTimeMillis() + 180000));
			break;
		case 3:
			// 第3次重试为十分钟以后开始执行
			builder.startAt(new Date(System.currentTimeMillis() + 600000));
			break;
		case 4:
			// 第4次重试为十五分钟以后开始执行
			builder.startAt(new Date(System.currentTimeMillis() + 900000));
			break;
		case 5:
			// 第5次重试为半小时以后开始执行
			builder.startAt(new Date(System.currentTimeMillis() + 1800000));
			break;
		default:
			// 之后的重试都是一小时以后开始执行
			builder.startAt(new Date(System.currentTimeMillis() + 3600000));
			break;
		}

		return builder.build();
	}
}
